import 'package:flutter/material.dart';
import 'dart:math';

class StatelessContainer extends StatelessWidget {
  final Color color;

  StatelessContainer({super.key}) : color = _generateRandomColor();

  static Color _generateRandomColor() {
    final Random random = Random();
    return Color.fromARGB(
      255,
      random.nextInt(256),
      random.nextInt(256),
      random.nextInt(256),
    );
  }

  @override
  Widget build(BuildContext context) {
    debugPrint("StatelessContainer, build");
    return Container(
      width: 100,
      height: 100,
      color: color,
    );
  }
}

class Screen extends StatefulWidget {
  const Screen({super.key});

  @override
  _ScreenState createState() => _ScreenState();
}

// 交换两个Widget
// static bool canUpdate(Widget oldWidget, Widget newWidget) {
//   return oldWidget.runtimeType == newWidget.runtimeType
//     && oldWidget.key == newWidget.key;
// }

// StatelessContainer比较的时候runtimeType相等，key为null也相等。
// 所以两个widget被交换了位置。StatelessElement调用新持有的Widget的build方法进行重新构建；
// 而color实际就存储在widget中，因此屏幕上的两个Widget被真正交换了顺序。

// StatefulContainer比较的时候，我们将color定义在了State中，Widget并不保存State，真正持有State的是StatefulElement.
// 当我们没有给 Widget 任何 key 的时候，将会只比较这两个 Widget 的 runtimeType 。
// 由于两个 Widget 的属性和方法都相同，canUpdate 方法将会返回 true，于是更新 StatefulWidget 的位置，这两个 Element 将不会交换位置。
// 但是原有 Element 只会从它持有的 state 实例中 build 新的 widget。因为 element 没变，它持有的 state 也没变。
// 所以颜色不会交换。这里变换 StatefulWidget 的位置是没有作用的。

// 而我们给 Widget 一个 key 之后，canUpdate 方法将会比较两个 Widget 的 runtimeType 以及 key。并返回 false。
// 此时 RenderObjectElement 会用新 Widget 的 key 在老 Element 列表里面查找，
// 找到匹配的则会更新 Element 的位置并更新对应 renderObject 的位置，
// 对于这个例子来讲就是交换了 Element 的位置并交换了对应 renderObject 的位置。都交换了，那么颜色自然也就交换了。

// 比较范围：为了提升性能 Flutter 的比较算法（diff）是有范围的，它并不是对第一个 StatefulWidget 进行比较，而是对某一个层级的 Widget 进行比较。
// 在 Flutter 的比较过程中它下到 Row 这个层级，发现它是一个 MultiChildRenderObjectWidget（多子部件的 Widget）。然后它会对所有 children 层逐个进行扫描。
// 在Column这一层级，padding 部分的 runtimeType 并没有改变，且不存在 Key。然后再比较下一个层级。
// 由于内部的 StatefulContainer 存在 key，新旧 key 不同，且现在的层级在 padding 内部，该层级没有多子 Widget。
// canUpdate 返回 flase，Flutter 的将会认为这个 Element 需要被替换。
// 然后重新生成一个新的 Element 对象装载到 Element 树上替换掉之前的 Element。第二个 Widget 同理。
//
// 为了解决这个问题，我们需要将 key 放到 Row 的 children 这一层级。此时StatefulContainer有没有key都已不再重要

class _ScreenState extends State<Screen> {
  //会进行交换
  // List<Widget> widgets = [
  //   StatelessContainer(),
  //   StatelessContainer(),
  // ];
  //不会进行交换
  // List<Widget> widgets = [
  //   StatefulContainer(),
  //   StatefulContainer(),
  // ];
  //会进行交换
  // List<Widget> widgets = [
  //   StatefulContainer(key:  UniqueKey()),
  //   StatefulContainer(key:  UniqueKey()),
  // ];
  //会重新创建
  // List<Widget> widgets = [
  //   Padding(
  //     padding: const EdgeInsets.all(8.0),
  //     child: StatefulContainer(key:  UniqueKey()),
  //   ),
  //   Padding(
  //     padding: const EdgeInsets.all(8.0),
  //     child: StatefulContainer(key:  UniqueKey()),
  //   )
  // ];
  //会重新创建
  // List<Widget> widgets = [
  //   Padding(
  //     key: UniqueKey(),
  //     padding: const EdgeInsets.all(8.0),
  //     child: StatefulContainer(key:  UniqueKey()),
  //   ),
  //   Padding(
  //     key: UniqueKey(),
  //     padding: const EdgeInsets.all(8.0),
  //     child: StatefulContainer(key:  UniqueKey()),
  //   )
  // ];
  //会重新创建
  List<Widget> widgets = [
    Padding(
      key: UniqueKey(),
      padding: const EdgeInsets.all(8.0),
      child: StatefulContainer(),
    ),
    Padding(
      key: UniqueKey(),
      padding: const EdgeInsets.all(8.0),
      child: StatefulContainer(),
    )
  ];

  @override
  void initState() {
    super.initState();
    debugPrint("_ScreenState, initState");
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    debugPrint("_ScreenState, didChangeDependencies");
  }

  @override
  void dispose() {
    super.dispose();
    debugPrint("_ScreenState, dispose");
  }

  @override
  Widget build(BuildContext context) {
    debugPrint("_ScreenState, build");
    return Scaffold(
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: widgets,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: switchWidget,
        child: const Icon(Icons.undo),
      ),
    );
  }

  switchWidget(){
    widgets.insert(0, widgets.removeAt(1));
    setState(() {});
  }
}


class StatefulContainer extends StatefulWidget {
  StatefulContainer({Key? key}) : super(key: key);
  @override
  _StatefulContainerState createState() => _StatefulContainerState();
}

class _StatefulContainerState extends State<StatefulContainer> {
  final Color color = StatelessContainer._generateRandomColor();

  @override
  Widget build(BuildContext context) {
    debugPrint("_StatefulContainerState, build ${widget.key == null}");
    return Container(
      width: 100,
      height: 100,
      color: color,
    );
  }
}